package org.jadelyre.core;

import org.jadelyre.core.codec.Packet;
import org.jadelyre.core.task.EntryQueue;
import org.jadelyre.core.task.Task;
import org.jadelyre.core.worker.Worker;

import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public abstract class AbstractChannel implements Channel {

    private final JadeLyre jadeLyre;
    //    private final Task<ByteBuffer> decodeTask;
    private final Worker<ByteBuffer> decodeWorker;
    //    private final Task<Packet> handleTask;
    private final Worker<Packet> handleWorker;
    //    private final Task<Packet> sendTask;
    private final Worker<Packet> sendWorker;
    private final ReadCompletionHandler readCompletionHandler;
    private final WriteCompletionHandler writeCompletionHandler;
    private final AsynchronousSocketChannel asynchronousSocketChannel;
    private NodeAddress remoteNodeAddress;
    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    private volatile boolean closing;
    private Task<Packet> heartbeatTask;


    public AbstractChannel(JadeLyre jadeLyre, AsynchronousSocketChannel asynchronousSocketChannel
            , NodeAddress remoteNodeAddress) {
        this.jadeLyre = jadeLyre;
        this.remoteNodeAddress = remoteNodeAddress;
//        this.decodeTask = new DecodeTask(this);
        this.decodeWorker = jadeLyre.getWorkerFactory().getDecodeWorker(this, new EntryQueue<ByteBuffer>());
//        this.handleTask = new HandleTask(this,jadeLyre.getHandler());
        this.handleWorker = jadeLyre.getWorkerFactory().getHandleWorker(this, new EntryQueue<Packet>());
//        this.sendTask = new SendTask(this);
        this.sendWorker = jadeLyre.getWorkerFactory().getWriteWorker(this, new EntryQueue<Packet>());
        this.asynchronousSocketChannel = asynchronousSocketChannel;
        this.readCompletionHandler = new ReadCompletionHandler(asynchronousSocketChannel);
        this.writeCompletionHandler = new WriteCompletionHandler(asynchronousSocketChannel);
    }

    public void setHeartbeatTask(Task<Packet> heartbeatTask) {
        this.heartbeatTask = heartbeatTask;
    }

    @Override
    public JadeLyre getJadeLyre() {
        return jadeLyre;
    }
//    @Override
//    public DecodeTask getDecodeTask() {
//        return (DecodeTask)this.decodeTask;
//    }

    //    @Override
//    public HandleTask getHandleTask() {
//        return (HandleTask)this.handleTask;
//    }
//    @Override
//    public SendTask getSendTask() {
//        return (SendTask)this.sendTask;
//    }
    @Override
    public Worker<ByteBuffer> getDecodeWorker() {
        return decodeWorker;
    }

    @Override
    public Worker<Packet> getHandleWorker() {
        return handleWorker;
    }

    @Override
    public Worker<Packet> getSendWorker() {
        return sendWorker;
    }

    @Override
    public ReadCompletionHandler getReadCompletionHandler() {
        return readCompletionHandler;
    }
    @Override
    public WriteCompletionHandler getWriteCompletionHandler() {
        return writeCompletionHandler;
    }
    @Override
    public AsynchronousSocketChannel getAsynchronousSocketChannel() {
        return asynchronousSocketChannel;
    }

    @Override
    public NodeAddress getRemoteNodeAddress() {
        return remoteNodeAddress;
    }

    @Override
    public void close() {
        if (readWriteLock.readLock().tryLock()){
            if (closing){
                return;
            }
            readWriteLock.readLock().unlock();
        }
        if (readWriteLock.writeLock().tryLock()){
            if (closing){
                return;
            }
            closing = true;
            readWriteLock.writeLock().unlock();
        }
//        jadeLyre.getCloseTask().addTask(this).execute();
    }
}
